﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace MyCoreLib.Automation.Data.SqlClient.Metadata
{
    public abstract class SqlDbObjectMetadataCollection<T> : KeyedCollection<string, T> where T : class, ISqlDbObjectMetadata
    {
        private static readonly Regex FullNameRegex;

        static SqlDbObjectMetadataCollection()
        {
            string fullNamePattern = @"(?:^ \s* @part (?:[.] @part ){0,2}  \s*$) | ^(?<mdf>\S+) (\. @part){2}$"
                .Replace("@part", @"(?:\s*@part\s*)")
                .Replace("@part", @"(?: \[ \s* @complex \s* \] |  @simple  )")
                .Replace("@complex", @"(?<part>\w+(?:\s+\w+)+)")
                .Replace("@simple", @"(?<part>\w+)");
            fullNamePattern = Regex.Replace(fullNamePattern, @"\s+", string.Empty);
            FullNameRegex = new Regex(fullNamePattern, RegexOptions.Compiled);
        }


        protected SqlDbObjectMetadataCollection()
            : base(StringComparer.OrdinalIgnoreCase, dictionaryCreationThreshold: 10)
        {
        }


        public T Find(IDbObject dbObject)
        {
            var genericDbObject = dbObject as GenericDbObject ?? new GenericDbObject(dbObject);
            if (Contains(genericDbObject.FullName))
            {
                return this[genericDbObject.FullName];
            }
            return null;
        }


        public virtual T FindByName(string name)
        {
            var match = FullNameRegex.Match(name);
            if (!match.Success)
            {
                return null;
            }
            var captures = match.Groups["part"].Captures;
            if (captures.Count == 3)
            {
                var dbObject = new GenericDbObject(captures[1].Value, captures[2].Value);
                return this[dbObject.FullName];
            }
            if (captures.Count == 2)
            {
                var dbObject = new GenericDbObject(captures[0].Value, captures[1].Value);
                return this[dbObject.FullName];
            }
            else
            {
                return Find(new GenericDbObject(name));
            }
        }

        protected override string GetKeyForItem(T item)
        {
            return item.FullName;
        }

        protected override void InsertItem(int index, T item)
        {
            if (Object.ReferenceEquals(item, null))
            {
                throw new ArgumentNullException("item");
            }
            base.InsertItem(index, item);
        }

        protected override void SetItem(int index, T item)
        {
            if (Object.ReferenceEquals(item, null))
            {
                throw new ArgumentNullException("item");
            }
            base.SetItem(index, item);
        }
       
    }
}
